// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: xguo, jhkim

#pragma once

#include <algorithm>
#include <deque>
#include <set>
#include <unordered_map>
#include <utility>
#include <vector>

#include "coin2/exchange/base/market/market_exchange_api.h"
#include "coin2/exchange/base/symbology/product.h"

namespace coin2::strategy::order_executor {

inline bool IsChinaFuturesPositionStyle(const MarketExchangeApi& mea) {
  using coin2::exchange::base::symbology::ExchangeType;
  using coin2::exchange::base::symbology::MarketType;
  return mea.market == MarketType::Futures &&
         (mea.exchange == ExchangeType::Huobi ||
          (mea.exchange == ExchangeType::Okex && (mea.api == "v3" || mea.api == "v3-swap")) ||
          mea == MarketExchangeApi{MarketType::Futures, ExchangeType::Bybit, "v2-linear"} ||
          mea == MarketExchangeApi{MarketType::Futures, ExchangeType::Bitget, "v1"});
}

class CoolDownLimiter {
 public:
  explicit CoolDownLimiter(int64_t cooldown_ns = 500'000'000L, int64_t cooldown_limit = 1)
      : cooldown_ns_(cooldown_ns), cooldown_limit_(cooldown_limit), trans_q_(), trans_d_() {}

  void ResizeCoolDown(int64_t cooldown_ns, int64_t cooldown_limit) {
    cooldown_ns_ = cooldown_ns;
    cooldown_limit_ = cooldown_limit;
    trans_q_.clear();
    trans_d_.clear();
  }

  void UpdateTimeOnly(int64_t timestamp) {
    while (!trans_q_.empty() && timestamp - trans_q_.front().first > cooldown_ns_) {
      int64_t proc_order_id = trans_q_.front().second;
      trans_d_[proc_order_id] -= 1;
      if (trans_d_[proc_order_id] == 0) {
        trans_d_.erase(proc_order_id);
      }
      trans_q_.pop_front();
    }
  }

  void Update(int64_t timestamp, int64_t proc_order_id) {
    trans_d_[proc_order_id] += 1;
    trans_q_.push_back(std::make_pair(timestamp, proc_order_id));
    UpdateTimeOnly(timestamp);
  }

  bool InCoolDown(int64_t timestamp, int64_t proc_order_id) {
    UpdateTimeOnly(timestamp);
    return trans_d_[proc_order_id] >= cooldown_limit_;
  }

 private:
  int64_t cooldown_ns_;
  int64_t cooldown_limit_;
  std::deque<std::pair<int64_t, int64_t>> trans_q_;
  std::unordered_map<int64_t, int64_t> trans_d_;
};  // class name CoolDownLimiter

}  // namespace coin2::strategy::order_executor
